home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -screenplay- / shareware / warpquake / warpquakesrc / snd_mix.c < prev    next >
C/C++ Source or Header  |  2000-02-29  |  9KB  |  470 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // snd_mix.c -- portable code to mix sounds for snd_dma.c
  21.  
  22. #include "quakedef.h"
  23.  
  24. #ifdef _WIN32
  25. #include "winquake.h"
  26. #else
  27. #define DWORD    unsigned long
  28. #endif
  29.  
  30. #define    PAINTBUFFER_SIZE    512
  31. portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
  32. int        snd_scaletable[32][256];
  33. int     *snd_p, snd_linear_count, snd_vol;
  34. short    *snd_out;
  35.  
  36. void Snd_WriteLinearBlastStereo16 (void);
  37.  
  38. #if    !id386
  39. void Snd_WriteLinearBlastStereo16 (void)
  40. {
  41.     int        i;
  42.     int        val;
  43.  
  44.     for (i=0 ; i<snd_linear_count ; i+=2)
  45.     {
  46.         val = (snd_p[i]*snd_vol)>>8;
  47.         if (val > 0x7fff)
  48.             snd_out[i] = 0x7fff;
  49.         else if (val < (short)0x8000)
  50.             snd_out[i] = (short)0x8000;
  51.         else
  52.             snd_out[i] = val;
  53.  
  54.         val = (snd_p[i+1]*snd_vol)>>8;
  55.         if (val > 0x7fff)
  56.             snd_out[i+1] = 0x7fff;
  57.         else if (val < (short)0x8000)
  58.             snd_out[i+1] = (short)0x8000;
  59.         else
  60.             snd_out[i+1] = val;
  61.     }
  62. }
  63. #endif
  64.  
  65. void S_TransferStereo16 (int endtime)
  66. {
  67.     int        lpos;
  68.     int        lpaintedtime;
  69.     DWORD    *pbuf;
  70. #ifdef _WIN32
  71.     int        reps;
  72.     DWORD    dwSize,dwSize2;
  73.     DWORD    *pbuf2;
  74.     HRESULT    hresult;
  75. #endif
  76.     
  77.     snd_vol = volume.value*256;
  78.  
  79.     snd_p = (int *) paintbuffer;
  80.     lpaintedtime = paintedtime;
  81.  
  82. #ifdef _WIN32
  83.     if (pDSBuf)
  84.     {
  85.         reps = 0;
  86.  
  87.         while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 
  88.                                        &pbuf2, &dwSize2, 0)) != DS_OK)
  89.         {
  90.             if (hresult != DSERR_BUFFERLOST)
  91.             {
  92.                 Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n");
  93.                 S_Shutdown ();
  94.                 S_Startup ();
  95.                 return;
  96.             }
  97.  
  98.             if (++reps > 10000)
  99.             {
  100.                 Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n");
  101.                 S_Shutdown ();
  102.                 S_Startup ();
  103.                 return;
  104.             }
  105.         }
  106.     }
  107.     else
  108. #endif
  109.     {
  110.         pbuf = (DWORD *)shm->buffer;
  111.     }
  112.  
  113.     while (lpaintedtime < endtime)
  114.     {
  115.     // handle recirculating buffer issues
  116.         lpos = lpaintedtime & ((shm->samples>>1)-1);
  117.  
  118.         snd_out = (short *) pbuf + (lpos<<1);
  119.  
  120.         snd_linear_count = (shm->samples>>1) - lpos;
  121.         if (lpaintedtime + snd_linear_count > endtime)
  122.             snd_linear_count = endtime - lpaintedtime;
  123.  
  124.         snd_linear_count <<= 1;
  125.  
  126.     // write a linear blast of samples
  127.         Snd_WriteLinearBlastStereo16 ();
  128.  
  129.         snd_p += snd_linear_count;
  130.         lpaintedtime += (snd_linear_count>>1);
  131.     }
  132.  
  133. #ifdef _WIN32
  134.     if (pDSBuf)
  135.         pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
  136. #endif
  137. }
  138.  
  139. void S_TransferPaintBuffer(int endtime)
  140. {
  141.     int     out_idx;
  142.     int     count;
  143.     int     out_mask;
  144.     int     *p;
  145.     int     step;
  146.     int        val;
  147.     int        snd_vol;
  148.  
  149. #ifdef AMIGA
  150.     int    offset;
  151.  
  152. #define NEXTVAL                       \
  153.     val = (*p++ * snd_vol) >> 16; \
  154.     if (val > 127)                \
  155.         val = 127;            \
  156.     else if (val < -128)          \
  157.         val = -128
  158.  
  159.     p = (int *) paintbuffer;
  160.     count = endtime - paintedtime;
  161.     offset = shm->samples >> 1;
  162.     out_mask = offset - 1;
  163.     out_idx = paintedtime & out_mask;
  164.     snd_vol = volume.value * 256;
  165.     {
  166.         unsigned char *out = (unsigned char *) shm->buffer;
  167.         int lval1, lval2;
  168.         while ((out_idx & 3) != 0 && count > 0)
  169.         {
  170.             NEXTVAL;
  171.             out[out_idx] = val;
  172.  
  173.             NEXTVAL;
  174.             out[out_idx + offset] = val;
  175.  
  176.             out_idx = (out_idx + 1) & out_mask;
  177.             count--;
  178.         }
  179.         while (count >= 4)
  180.         {
  181.             NEXTVAL;
  182.             lval1 = val;
  183.             NEXTVAL;
  184.             lval2 = val;
  185.             NEXTVAL;
  186.             lval1 = (lval1 << 8) | (val & 255);
  187.             NEXTVAL;
  188.             lval2 = (lval2 << 8) | (val & 255);
  189.             NEXTVAL;
  190.             lval1 = (lval1 << 8) | (val & 255);
  191.             NEXTVAL;
  192.             lval2 = (lval2 << 8) | (val & 255);
  193.             NEXTVAL;
  194.             lval1 = (lval1 << 8) | (val & 255);
  195.             NEXTVAL;
  196.             lval2 = (lval2 << 8) | (val & 255);
  197.  
  198.             *(int *)(&out[out_idx]) = lval1;
  199.             *(int *)(&out[out_idx + offset]) = lval2;
  200.  
  201.             out_idx = (out_idx + 4) & out_mask;
  202.  
  203.             count -= 4;
  204.         }
  205.         while (count > 0)
  206.         {
  207.             NEXTVAL;
  208.             out[out_idx] = val;
  209.  
  210.             NEXTVAL;
  211.             out[out_idx + offset] = val;
  212.  
  213.             out_idx = (out_idx + 1) & out_mask;
  214.             count--;
  215.         }
  216.     }
  217. #else
  218.     DWORD    *pbuf;
  219. #ifdef _WIN32
  220.     int        reps;
  221.     DWORD    dwSize,dwSize2;
  222.     DWORD    *pbuf2;
  223.     HRESULT    hresult;
  224. #endif
  225.  
  226.     if (shm->samplebits == 16 && shm->channels == 2)
  227.     {
  228.         S_TransferStereo16 (endtime);
  229.         return;
  230.     }
  231.     
  232.     p = (int *) paintbuffer;
  233.     count = (endtime - paintedtime) * shm->channels;
  234.     out_mask = shm->samples - 1; 
  235.     out_idx = paintedtime * shm->channels & out_mask;
  236.     step = 3 - shm->channels;
  237.     snd_vol = volume.value*256;
  238.  
  239. #ifdef _WIN32
  240.     if (pDSBuf)
  241.     {
  242.         reps = 0;
  243.  
  244.         while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 
  245.                                        &pbuf2,&dwSize2, 0)) != DS_OK)
  246.         {
  247.             if (hresult != DSERR_BUFFERLOST)
  248.             {
  249.                 Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n");
  250.                 S_Shutdown ();
  251.                 S_Startup ();
  252.                 return;
  253.             }
  254.  
  255.             if (++reps > 10000)
  256.             {
  257.                 Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n");
  258.                 S_Shutdown ();
  259.                 S_Startup ();
  260.                 return;
  261.             }
  262.         }
  263.     }
  264.     else
  265. #endif
  266.     {
  267.         pbuf = (DWORD *)shm->buffer;
  268.     }
  269.  
  270.     if (shm->samplebits == 16)
  271.     {
  272.         short *out = (short *) pbuf;
  273.         while (count--)
  274.         {
  275.             val = (*p * snd_vol) >> 8;
  276.             p+= step;
  277.             if (val > 0x7fff)
  278.                 val = 0x7fff;
  279.             else if (val < (short)0x8000)
  280.                 val = (short)0x8000;
  281.             out[out_idx] = val;
  282.             out_idx = (out_idx + 1) & out_mask;
  283.         }
  284.     }
  285.     else if (shm->samplebits == 8)
  286.     {
  287.         unsigned char *out = (unsigned char *) pbuf;
  288.         while (count--)
  289.         {
  290.             val = (*p * snd_vol) >> 8;
  291.             p+= step;
  292.             if (val > 0x7fff)
  293.                 val = 0x7fff;
  294.             else if (val < (short)0x8000)
  295.                 val = (short)0x8000;
  296.             out[out_idx] = (val>>8) + 128;
  297.             out_idx = (out_idx + 1) & out_mask;
  298.         }
  299.     }
  300.  
  301. #ifdef _WIN32
  302.     if (pDSBuf) {
  303.         DWORD dwNewpos, dwWrite;
  304.         int il = paintedtime;
  305.         int ir = endtime - paintedtime;
  306.         
  307.         ir += il;
  308.  
  309.         pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
  310.  
  311.         pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite);
  312.  
  313. //        if ((dwNewpos >= il) && (dwNewpos <= ir))
  314. //            Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos);
  315.     }
  316. #endif
  317. #endif
  318. }
  319.  
  320.  
  321. /*
  322. ===============================================================================
  323.  
  324. CHANNEL MIXING
  325.  
  326. ===============================================================================
  327. */
  328.  
  329. void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);
  330. void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);
  331.  
  332. void S_PaintChannels(int endtime)
  333. {
  334.     int     i;
  335.     int     end;
  336.     channel_t *ch;
  337.     sfxcache_t    *sc;
  338.     int        ltime, count;
  339.  
  340.     while (paintedtime < endtime)
  341.     {
  342.     // if paintbuffer is smaller than DMA buffer
  343.         end = endtime;
  344.         if (endtime - paintedtime > PAINTBUFFER_SIZE)
  345.             end = paintedtime + PAINTBUFFER_SIZE;
  346.  
  347.     // clear the paint buffer
  348.         Q_memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
  349.  
  350.     // paint in the channels.
  351.         ch = channels;
  352.         for (i=0; i<total_channels ; i++, ch++)
  353.         {
  354.             if (!ch->sfx)
  355.                 continue;
  356.             if (!ch->leftvol && !ch->rightvol)
  357.                 continue;
  358.             sc = S_LoadSound (ch->sfx);
  359.             if (!sc)
  360.                 continue;
  361.  
  362.             ltime = paintedtime;
  363.  
  364.             while (ltime < end)
  365.             {    // paint up to end
  366.                 if (ch->end < end)
  367.                     count = ch->end - ltime;
  368.                 else
  369.                     count = end - ltime;
  370.  
  371.                 if (count > 0)
  372.                 {    
  373.                     if (sc->width == 1)
  374.                         SND_PaintChannelFrom8(ch, sc, count);
  375.                     else
  376.                         SND_PaintChannelFrom16(ch, sc, count);
  377.     
  378.                     ltime += count;
  379.                 }
  380.  
  381.             // if at end of loop, restart
  382.                 if (ltime >= ch->end)
  383.                 {
  384.                     if (sc->loopstart >= 0)
  385.                     {
  386.                         ch->pos = sc->loopstart;
  387.                         ch->end = ltime + sc->length - ch->pos;
  388.                     }
  389.                     else                
  390.                     {    // channel just stopped
  391.                         ch->sfx = NULL;
  392.                         break;
  393.                     }
  394.                 }
  395.             }
  396.                                                               
  397.         }
  398.  
  399.     // transfer out according to DMA format
  400.         S_TransferPaintBuffer(end);
  401.         paintedtime = end;
  402.     }
  403. }
  404.  
  405. void SND_InitScaletable (void)
  406. {
  407.     int        i, j;
  408.     
  409.     for (i=0 ; i<32 ; i++)
  410.         for (j=0 ; j<256 ; j++)
  411.             snd_scaletable[i][j] = ((signed char)j) * i * 8;
  412. }
  413.  
  414.  
  415. #if    !id386
  416.  
  417. void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
  418. {
  419.     int     data;
  420.     int        *lscale, *rscale;
  421.     unsigned char *sfx;
  422.     int        i;
  423.  
  424.     if (ch->leftvol > 255)
  425.         ch->leftvol = 255;
  426.     if (ch->rightvol > 255)
  427.         ch->rightvol = 255;
  428.         
  429.     lscale = snd_scaletable[ch->leftvol >> 3];
  430.     rscale = snd_scaletable[ch->rightvol >> 3];
  431.     sfx = (signed char *)sc->data + ch->pos;
  432.  
  433.     for (i=0 ; i<count ; i++)
  434.     {
  435.         data = sfx[i];
  436.         paintbuffer[i].left += lscale[data];
  437.         paintbuffer[i].right += rscale[data];
  438.     }
  439.     
  440.     ch->pos += count;
  441. }
  442.  
  443. #endif    // !id386
  444.  
  445.  
  446. void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
  447. {
  448.     int data;
  449.     int left, right;
  450.     int leftvol, rightvol;
  451.     signed short *sfx;
  452.     int    i;
  453.  
  454.     leftvol = ch->leftvol;
  455.     rightvol = ch->rightvol;
  456.     sfx = (signed short *)sc->data + ch->pos;
  457.  
  458.     for (i=0 ; i<count ; i++)
  459.     {
  460.         data = sfx[i];
  461.         left = (data * leftvol) >> 8;
  462.         right = (data * rightvol) >> 8;
  463.         paintbuffer[i].left += left;
  464.         paintbuffer[i].right += right;
  465.     }
  466.  
  467.     ch->pos += count;
  468. }
  469.  
  470.